//
// Created by Alex on 17/3/10.
//

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/eventfd.h>

#include "libev.h"



// ms
uint64_t GetNow() {
    timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

void TimerInit(TimeEvent *ev, EventProc proc, uint64_t tv,
               uint64_t repeat) {
    ev->m_active = 0;
    ev->m_priority = kHighPriority;
    ev->m_pending = 0;
    ev->m_repeat = repeat < 0 ? 0 : repeat;
    ev->m_absTime = tv + GetNow();
    ev->m_timeId = 0;
    ev->m_proc = proc;
}

void TimerInit(TimeEvent *ev, EventProc proc, timeval tv) {
    TimerInit(ev, proc, tv.tv_sec * 1000 + tv.tv_usec / 1000, 0);
}

void TimerInit(TimeEvent *ev, EventProc proc, timeval tv, timeval repeat) {
    TimerInit(ev, proc, tv.tv_sec * 1000 + tv.tv_usec / 1000,
              repeat.tv_sec * 1000 + repeat.tv_usec / 1000);
}

void SignalInit(SignalEvent *ev, EventProc proc, int signum) {
    ev->m_active = 0;
    ev->m_priority = kHighPriority;
    ev->m_pending = 0;
    ev->m_signum = signum;
    ev->m_proc = proc;
}

void AsyncInit(AsyncEvent *ev, EventProc proc) {
    ev->m_active = 0;
    ev->m_priority = kLowPriority;
    ev->m_pending = 0;
    ev->m_asyncId = 0;
    ev->m_send = 0;
    ev->m_proc = proc;
}

void IoInit(IoEvent *ev, EventProc proc, int fd, int events) {
    ev->m_active = 0;
    ev->m_priority = kLowPriority;
    ev->m_pending = 0;
    ev->m_fd = fd;
    ev->m_events = events;
    ev->m_proc = proc;
}

void ChildInit(ChildEvent *ev, EventProc proc, int pid) {
    ev->m_active = 0;
    ev->m_priority = kHighPriority;
    ev->m_pending = 0;
    ev->m_pid = pid;
    ev->m_status = 0;
    ev->m_proc = proc;
}

void EventInit(Event *ev, EventProc proc) {
    ev->m_active = 0;
    ev->m_priority = kLowPriority;
    ev->m_pending = 0;
    ev->m_proc = proc;
}


static inline void AddNodeToList(EventNode **node, EventNode *elem) {
  elem->m_next = *node;
  *node = elem;
}

static inline void DelNodeList(EventNode **head, EventNode *elem) {
  EventNode *cur = *head;
  EventNode *prev = NULL;
  while (cur) {
    if (cur == elem) {
      if (*head == elem) {
        *head = elem->m_next;
      } else {
        prev->m_next = elem->m_next;
      }
      break;
    }
    prev = cur;
    cur = cur->m_next;
  }
}

void EventLoop::SignalFdProc(Event *event, int revent) {
  signalfd_siginfo si[2], *sip;
  while (1) {
    ssize_t res = read(m_sigFd, si, sizeof(si));

    for (sip = si; (char *) sip < (char *) si + res; ++sip) {
      AddSignalEvent(sip->ssi_signo);
    }

    if (res < (ssize_t) sizeof(si)) {
      break;
    }
  }
}

void EventLoop::AsyncFdProc(Event *event, int revent) {
  if (revent & kReadEvent) {
    if (m_eventFd >= 0) {
      uint64_t counter;
      read(m_eventFd, &counter, sizeof(uint64_t));
    } else if (m_eventPipe[0] >= 0) {
      char dummy;
      read(m_eventPipe[0], &dummy, sizeof(char));
    }
    for (int i = 0; i < m_asyncs.size(); ++i) {
      if (m_asyncs[i]->m_send == 1) {
        m_asyncs[i]->m_send = 0;
        FeedEvent(m_asyncs[i], kAsyncEvent);
      }
    }
  }
}

void EventLoop::ChildSigalProc(Event *event, int revent) {
  int pid, status;
  while (1) {
    pid = waitpid(-1, &status, WNOHANG | WUNTRACED);
    if (pid <= 0) {
      break;
    } else {
      AddChildEvent(pid, status);
    }
  }
}

EventLoop::EventLoop(bool enableChild)
    : m_stop(true), m_enableChild(enableChild), m_now(GetNow()), m_activeCnt(0),
      m_epollFd(-1), m_epollEvents(NULL), m_epollEventMax(0), m_sigFd(-1),
      m_eventFd(-1) {

  m_eventPipe[0] = m_eventPipe[1] = -1;

  for (int i = 0; i < 128; ++i) {
    m_signals[i] = NULL;
  }

  m_epollFd = epoll_create(256);

  fcntl(m_epollFd, F_SETFD, FD_CLOEXEC);

  m_epollEventMax = 64;
  m_epollEvents = new epoll_event[m_epollEventMax];

  if (m_enableChild) {
    SignalInit(&m_childEvent, (EventProc) &EventLoop::ChildSigalProc, SIGCHLD);
    m_childEvent.m_priority = kHighPriority;

    SignalStart(&m_childEvent);
    m_activeCnt = m_activeCnt - 1;
  }
}

EventLoop::~EventLoop() {
  close(m_epollFd);
  delete m_epollEvents;

  if (m_sigFd > 0) {
    close(m_sigFd);
  }
}

void EventLoop::ExitLoop() { m_stop = true; }

void EventLoop::Dispath() {
  m_stop = false;

  do {
    // Loop 之前
    for (int i = 0; i < m_afterEvent.size(); ++i) {
      FeedEvent(m_afterEvent[i], kAfterLoop);
    }


    if (m_stop) {
      break;
    }
    // 修改 io 事件
    ReifyFdChanges();

    uint64_t now = GetNow();
    // 超时
    int timeout = m_timers.GetTimeout(now);

    timeout = timeout < 0 ? -1 : timeout;

    // epoll
    PollEpoll(timeout);

    // timers
    ReifyTimers();

    // Loop之后

    for (int i = 0; i < m_beforeEvent.size(); ++i) {
      FeedEvent(m_beforeEvent[i], kBeforeLoop);
    }


    // Invoke Pending
    InvokePendings();

  } while (!m_stop && m_activeCnt > 0);
}

void EventLoop::IoStart(IoEvent *ioEv) {
  if (ioEv->m_active) {
    return;
  }
  StartEvent(ioEv);

  AddNodeToList(&m_anfds[ioEv->m_fd].m_head, ioEv);
  m_anfds[ioEv->m_fd].m_cnt += 1;

  AddFdChanges(ioEv->m_fd);
}

void EventLoop::IoStop(IoEvent *ioEv) {
  ClearPending(ioEv);

  if (!ioEv->m_active) {
    return;
  }

  DelNodeList(&m_anfds[ioEv->m_fd].m_head, ioEv);
  m_anfds[ioEv->m_fd].m_cnt -= 1;

  StopEvent(ioEv);
  AddFdChanges(ioEv->m_fd);
}

void EventLoop::TimeStart(TimeEvent *timeEv) {
  if (timeEv->m_active) {
    return;
  }

  StartEvent(timeEv);
  m_timers.AddTimer(timeEv);
}

void EventLoop::TimeStop(TimeEvent *timeEv) {
  ClearPending(timeEv);

  if (!timeEv->m_active) {
    return;
  }

  StopEvent(timeEv);
  m_timers.RemoveTimer(timeEv);
}

void EventLoop::SignalStart(SignalEvent *sigEv) {
  if (sigEv->m_active) {
    return;
  }

  if (m_sigFd < 0) {
    m_sigFd = signalfd(-1, &m_sigset, SFD_NONBLOCK | SFD_CLOEXEC);
    if (m_sigFd < 0 && errno == EINVAL) {
      m_sigFd = signalfd(-1, &m_sigset, 0);
    }

    if (m_sigFd >= 0) {
      fcntl(m_sigFd, F_SETFD, FD_CLOEXEC);
      fcntl(m_sigFd, F_SETFL, O_NONBLOCK);

      sigemptyset(&m_sigset);
      m_sigFdEvent.m_priority = kHighPriority;
      IoInit(&m_sigFdEvent, (EventProc) &EventLoop::SignalFdProc, m_sigFd,
             kReadEvent);
      IoStart(&m_sigFdEvent);
      m_activeCnt -= 1;
    }
  }

  if (m_sigFd >= 0) {
    sigaddset(&m_sigset, sigEv->m_signum);
    sigprocmask(SIG_BLOCK, &m_sigset, 0);
    signalfd(m_sigFd, &m_sigset, 0);

    StartEvent(sigEv);
    AddNodeToList(&m_signals[sigEv->m_signum - 1], sigEv);
  }
}

void EventLoop::SignalStop(SignalEvent *sigEv) {
  ClearPending(sigEv);
  if (!sigEv->m_active) {
    return;
  }

  if (m_signals[sigEv->m_signum - 1] == NULL) {
    if (m_sigFd >= 0) {
      sigset_t sigset;
      sigemptyset(&sigset);

      sigaddset(&sigset, sigEv->m_signum);
      sigdelset(&m_sigset, sigEv->m_signum);

      signalfd(m_sigFd, &m_sigset, 0);
      sigprocmask(SIG_UNBLOCK, &sigset, 0);

    } else {

      signal(sigEv->m_signum, SIG_DFL);
    }
  }

  DelNodeList(&m_signals[sigEv->m_signum - 1], sigEv);
  StopEvent(sigEv);
}

void EventLoop::SendAsync(AsyncEvent *async) {
  if (async->m_send == 1) {
    return;
  }

  if (m_eventFd >= 0) {
    async->m_send = 1;
    uint64_t counter;
    write(m_eventFd, &counter, sizeof(uint64_t));
  } else if (m_eventPipe[1] > 0) {
    async->m_send = 1;
    char dummy;
    write(m_eventPipe[1], &dummy, sizeof(char));
  }
}

void EventLoop::StopAsync(AsyncEvent *async) {
  ClearPending(async);
  if (!async->m_active) {
    return;
  }

  int position = async->m_asyncId - 1;
  if (position >= m_asyncs.size()) {
    return;
  }

  std::swap(m_asyncs[position], m_asyncs[m_asyncs.size() - 1]);
  m_asyncs.pop_back();

  async->m_asyncId = 0;
  if (!m_asyncs.empty()) {
    m_asyncs[position]->m_asyncId = position;
  }
  StopEvent(async);
}

void EventLoop::StartAsync(AsyncEvent *async) {
  if (async->m_active) {
    return;
  }

  if (async->m_asyncId > 0) {
    return;
  }

  if (m_eventFd < 0) {
    m_eventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if (m_eventFd < 0 && errno == EINVAL) {
      m_eventFd = eventfd(0, 0);
    }

    if (m_eventFd >= 0) {
      IoInit(&m_asyncEv, (EventProc) &EventLoop::AsyncFdProc, m_eventFd,
             kReadEvent);
      IoStart(&m_asyncEv);
      m_activeCnt = m_activeCnt - 1;

    } else {

      pipe(m_eventPipe);
      fcntl(m_eventPipe[0], F_SETFD, FD_CLOEXEC);
      fcntl(m_eventPipe[0], F_SETFL, O_NONBLOCK);

      fcntl(m_eventPipe[1], F_SETFD, FD_CLOEXEC);
      fcntl(m_eventPipe[1], F_SETFL, O_NONBLOCK);

      IoInit(&m_asyncEv, (EventProc) &EventLoop::AsyncFdProc, m_eventPipe[0],
             kReadEvent);
      IoStart(&m_asyncEv);
      m_activeCnt = m_activeCnt - 1;
    }
  }

  async->m_asyncId = m_asyncs.size();
  m_asyncs.push_back(async);

  StartEvent(async);
}

void EventLoop::StartChild(ChildEvent *childEv) {
  if (childEv->m_active) {
    return;
  }

  StartEvent(childEv);
  m_childs.insert(std::make_pair(childEv->m_pid, childEv));
}

void EventLoop::StopChild(ChildEvent *childEv) {
  ClearPending(childEv);
  if (!childEv->m_active) {
    return;
  }

  std::pair<ChildMapIt, ChildMapIt> pos = m_childs.equal_range(childEv->m_pid);
  while (pos.first != pos.second) {
    if (pos.first->second == childEv) {
      m_childs.erase(pos.first);
    } else {
      ++pos.first;
    }
  }

  StopEvent(childEv);
}

void EventLoop::StartBeforeLoop(BeforeLoopEvent *loopEvent) {
  if (loopEvent->m_active) {
    return;
  }
  loopEvent->m_priority = kHighPriority;
  m_beforeEvent.push_back(loopEvent);
  StartEvent(loopEvent);
}

void EventLoop::StopBeforeLoop(BeforeLoopEvent *loopEvent) {
  ClearPending(loopEvent);
  if (!loopEvent->m_active) {
    return;
  }

  for (int i = 0; i < m_beforeEvent.size(); ++i) {
    if (m_beforeEvent[i] == loopEvent) {
      m_beforeEvent.erase(m_beforeEvent.begin() + i);
      break;
    }
  }
  StopEvent(loopEvent);
}

void EventLoop::StartAfterLoop(AfterLoopEvent *loopEvent) {
  if (loopEvent->m_active) {
    return;
  }
  loopEvent->m_priority = kLowPriority;
  m_afterEvent.push_back(loopEvent);
  StartEvent(loopEvent);
}

void EventLoop::StopAfterLoop(AfterLoopEvent *loopEvent) {
  ClearPending(loopEvent);
  if (!loopEvent->m_active) {
    return;
  }

  for (int i = 0; i < m_afterEvent.size(); ++i) {
    if (m_afterEvent[i] == loopEvent) {
      m_afterEvent.erase(m_afterEvent.begin() + i);
      break;
    }
  }
  StopEvent(loopEvent);
}

void EventLoop::StartEvent(Event *event) {
  event->m_active = 1;
  m_activeCnt += 1;
}

void EventLoop::StopEvent(Event *event) {
  event->m_active = 0;
  m_activeCnt -= 1;
}

void EventLoop::AddFdChanges(int fd) {
  if (m_anfds[fd].m_reify == 0) {
    // m_reify = 1, 要 ReifyFdChanges之前已经修改过
    m_fdChanges.push_back(fd);
    m_anfds[fd].m_reify = 1;
  }
}

void EventLoop::ReifyFdChanges() {
  for (int i = 0; i < m_fdChanges.size(); ++i) {
    int fd = m_fdChanges[i];
    Anfd &anfd = m_anfds[fd];

    unsigned char old_events = anfd.m_events;
    unsigned char old_reify = anfd.m_reify;
    anfd.m_reify = 0; // 置为未修改

    if (old_reify) // 有修改过，则算一下现在的events值
    {
      for (EventNode *cur = anfd.m_head; cur != NULL; cur = cur->m_next) {
        IoEvent *ioEv = (IoEvent *) cur;

        anfd.m_events |= ioEv->m_events;
      }

      old_reify =
          (old_events != anfd.m_events ? 1 : 0); // 之前修改和 现在是否一样
    }

    if (old_reify == 1) {
      ModifyEpoll(fd, old_events, anfd.m_events); //添加或修改为新事件
    }

    if (m_anfds[fd].m_cnt == 0) {
      m_anfds[fd].Reset();
    }
  }
  m_fdChanges.clear();
}

void EventLoop::ClearPending(Event *ev) {
  if (ev->m_pending > 0) {
    int pri = ev->m_priority - 1;
    Pending &pending = m_pendings[pri][ev->m_pending - 1];
    pending.m_event == NULL;
    pending.m_revents = 0;
    ev->m_pending = 0;
  }
}

void EventLoop::PollEpoll(int timeout) {
  int eventCnt = epoll_wait(m_epollFd, m_epollEvents, m_epollEventMax, timeout);

  if (eventCnt < 0 && errno != EINTR) {
    return;
  }

  for (int i = 0; i < eventCnt; ++i) {
    epoll_event *ev = &m_epollEvents[i];

    int fd = (int) ev->data.u64;
    int want = m_anfds[fd].m_events;

    int got = (ev->events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? kReadEvent : 0) |
              (ev->events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? kWriteEvent : 0);

    if ((got & ~want) > 0) {

      ev->events = (want & kReadEvent ? EPOLLIN : 0) |
                   (want & kWriteEvent ? EPOLLOUT : 0);

      if (epoll_ctl(m_epollFd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev)) {
        continue;
      }
    }

    AddFdEvent(fd, got);
  }

  // 扩大 epoll_events
  if (eventCnt == m_epollEventMax) {
    delete[] m_epollEvents;
    m_epollEventMax = m_epollEventMax * 2;
    m_epollEvents = new epoll_event[m_epollEventMax];
  }
}

void EventLoop::ModifyEpoll(int fd, int oldEvents, int newEvents) {
  if (oldEvents == newEvents) {
    return;
  }

  unsigned char oldMask = m_anfds[fd].m_epollMask;

  epoll_event ev;
  ev.data.u64 = fd;
  ev.events = ((newEvents & kReadEvent) ? EPOLLIN : 0) |
              ((newEvents & kWriteEvent) ? EPOLLOUT : 0);

  // 旧与新的不一样，需要修改 epoll
  if (oldMask != ev.events) {
    bool optRet = false;
    do {
      if (epoll_ctl(m_epollFd,
                    (!oldMask && newEvents) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd,
                    &ev) == 0) {
        optRet = true;
        break;
      }

      if (errno == ENOENT) // 出错, 重试一次
      {
        if (epoll_ctl(m_epollFd, EPOLL_CTL_MOD, fd, &ev) == 0) {
          optRet = true;
          break;
        }

      } else if (errno == EEXIST) {
        if (!epoll_ctl(m_epollFd, EPOLL_CTL_MOD, fd, &ev) == 0) {
          optRet = true;
          break;
        }
      }

    } while (0);

    if (optRet) {
      m_anfds[fd].m_epollMask = ev.events;
    }
  }
}

void EventLoop::ReifyTimers() {
  uint64_t now = GetNow();
  TimeEvent *timeEv = NULL;
  while (1) {
    timeEv = m_timers.GetTimeoutEvent(now);
    if (timeEv != NULL) {
      FeedEvent(timeEv, kTimeoutEvent);
      if (timeEv->m_repeat > 0) {
        timeEv->m_absTime = timeEv->m_repeat + GetNow();
        m_timers.AddTimer(timeEv);
      } else {
        StopEvent(timeEv);
      }
    } else {
      break;
    }
  }
}

void EventLoop::FeedEvent(Event *ev, int revents) {
  int pri = ev->m_priority - 1;
  if (ev->m_pending > 0) // 事件已经发生
  {
    m_pendings[pri][ev->m_pending - 1].m_revents |= revents;

  } else {
    ev->m_pending = m_pendings[pri].m_cnt + 1;
    Pending &pending = m_pendings[pri][ev->m_pending - 1];
    pending.m_event = ev;
    pending.m_revents = revents;
    m_pendings[pri].m_cnt += 1;
  }
}

void EventLoop::AddFdEvent(int fd, int revents) {
  Anfd &anfd = m_anfds[fd];
  for (EventNode *event = anfd.m_head; event != NULL; event = event->m_next) {
    IoEvent *ioEv = (IoEvent *) event;
    int ev = ioEv->m_events & revents;
    if (ev) {
      FeedEvent(ioEv, ev);
    }
  }
}

void EventLoop::AddSignalEvent(int signum) {
  SignalEvent *sigEv = (SignalEvent *) m_signals[signum - 1];
  if (sigEv != NULL) {
    for (EventNode *cur = sigEv; cur != NULL; cur = cur->m_next) {
      FeedEvent(cur, kSignalEvent);
    }
  }
}

void EventLoop::AddChildEvent(int pid, int status) {

  std::pair<ChildMapIt, ChildMapIt> pos = m_childs.equal_range(pid);
  while (pos.first != pos.second) {
    ChildEvent *childEv = pos.first->second;

    childEv->m_priority = kHighPriority;
    childEv->m_pid = pid;
    FeedEvent(childEv, kChildEvent);

    ++pos.first;
  }
}

void EventLoop::InvokePendings() {
  for (int pri = kHighPriority - 1; pri >= kLowPriority - 1; --pri) {
    Array<Pending> &pendings = m_pendings[pri];

    while (pendings.m_cnt > 0) {
      Pending pending = pendings[pendings.m_cnt - 1];
      pendings.m_cnt -= 1;

      if (pending.m_event != nullptr && pending.m_event->m_pending > 0) {
        pending.m_event->m_pending = 0;
        pending.m_event->m_proc(this, pending.m_event, pending.m_revents);
      }
    }
  }
}
